<?php

/*
	info: 模板类
	$Id: template.class.php 14 2011-08-29 08:48:19Z lfly1573@gmail.com $
*/

if (!defined('WEB_IN'))
{
	header("HTTP/1.0 404 Not Found");
	exit();
}

class Template
{
	private $cssLinkFolder = '';
	private $cssObjFile = '';
	private $cssObjFolder = '';
	private $cssTplFile = '';

	private $htmObjFile = '';
	private $htmObjFolder = '';
	private $htmTplFile = '';

	private $templateName = '';

	private $tplFolder = '';
	private $tplDefaultFolder = '';

	private $vars = array();

	/**
	 * 构造函数
	 * @param $strTemplate 模板名称
	 * @return void
	 */
	public function __construct($strTemplate = '')
	{
		$this->templateName = ($strTemplate != '') ? $strTemplate : WEB_TEMPLATE;
		$this->tplFolder = WEB_ROOT.'/templates/'.$this->templateName;
		$this->tplDefaultFolder = WEB_ROOT.'/templates/default';
		$this->htmObjFolder = WEB_ROOT.'/cache/templates/'.$this->templateName;
		$this->cssObjFolder = WEB_ROOT.'/images/'.$this->templateName;
		$this->cssLinkFolder = WEB_PATH.'/images/'.$this->templateName;
	}

	/**
	 * 指派变量赋值
	 * @param $strKey 变量名称
	 * @param $mixValue 变量取值
	 * @return void
	 */
	public function Assign($strKey, $mixValue)
	{
		$this->vars[$strKey] = $mixValue;
	}

	/**
	 * 显示内容
	 * @param $strFile 模板文件
	 * @return void
	 */
	public function Display($strFile)
	{
		$this->AddVars();
		extract($this->vars, EXTR_SKIP);
		if (function_exists('ob_gzhandler'))
		{
			ob_start('ob_gzhandler');
			$webServer['bufferState'] = 1;
		}
		else
		{
			ob_start();
		}
		include $this->GetHtmFile($strFile);
		ob_end_flush();
	}

	/**
	 * 获取内容
	 * @param $strFile 模板文件
	 * @return string 解析后的内容
	 */
	public function Fetch($strFile)
	{
		$this->AddVars();
		extract($this->vars, EXTR_SKIP);
		ob_start();
		include $this->GetHtmFile($strFile);
		$tempContent = ob_get_contents();
		ob_end_clean();
		return $tempContent;
	}


	/******************************************************************/


	/* 增加系统变量 */
	private function AddVars()
	{
		$this->Assign('user', Lfly::$user);
		$this->Assign('webCache', Lfly::$webCache);
		$this->Assign('webConfig', Lfly::$webConfig);
		$this->Assign('webCookie', Lfly::$webCookie);
		$this->Assign('webGlobal', Lfly::$webGlobal);
		$this->Assign('webLang', Lfly::$webLang);
		$this->Assign('webRequest', Lfly::$webRequest);
		$this->Assign('webServer', Lfly::$webServer);
	}

	/* css模板编译 */
	private function CompileCss()
	{
		$tempContent = @file_get_contents($this->cssTplFile);
		if ($tempContent === FALSE)
		{
			exit('Can not load template file: '.basename($this->cssTplFile).'.');
		}

		if (!is_dir(dirname($this->cssObjFile)))
		{
			FileSystem::CreateFolder(dirname($this->cssObjFile));
		}

		$tempContent = preg_replace("/^\<\!\-\-\s*ENCODE\s+(.+)\s+\-\-\>$/ies", "Encryption::DoOp(base64_decode('\\1'), WEB_TEMPLATE_KEY)", trim($tempContent));

		$tempContent = str_replace("{WEB_PATH}", WEB_PATH, $tempContent);
		$tempContent = str_replace("{WEB_TEMPLATE}", WEB_TEMPLATE, $tempContent);
		$tempContent = str_replace("{WEB_IMAGE}", WEB_IMAGE, $tempContent);
		$tempContent = str_replace("{WEB_ADMIN}", WEB_ADMIN, $tempContent);

		$tempContent = preg_replace("/\s*\{\s*/", "{", $tempContent);
		$tempContent = preg_replace("/\s*:\s*/", ":", $tempContent);
		$tempContent = preg_replace("/\s*;\s*/", ";", $tempContent);
		$tempContent = preg_replace("/\s*\}\s+/", "}\n", $tempContent);

		if (!@$fp = fopen($this->cssObjFile, 'wb'))
		{
			exit('Can not write template file: '.basename($this->cssObjFile).'.');
		}
		flock($fp, LOCK_EX);
		fwrite($fp, trim($tempContent));
		flock($fp, LOCK_UN);
		fclose($fp);
		@chmod($this->cssObjFile, 0777);
	}

	/* htm模板编译 */
	private function CompileHtm()
	{
		$tempContent = @file_get_contents($this->htmTplFile);
		if ($tempContent === FALSE)
		{
			exit('Can not load template file: '.basename($this->htmTplFile).'.');
		}

		if (!is_dir(dirname($this->htmObjFile)))
		{
			FileSystem::CreateFolder(dirname($this->htmObjFile));
		}

		$tempVarFormat = "((?:\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*(?:\-\>(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\]|\(.*?\)(?=\}|\-\>|\s))*)*)";
		$tempConstFormat = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";

		$tempContent = preg_replace("/^\<\!\-\-\s*ENCODE\s+(.+)\s+\-\-\>$/ies", "Encryption::DoOp(base64_decode('\\1'), WEB_TEMPLATE_KEY)", trim($tempContent));
		$tempContent = preg_replace("/\<\!\-\-\s*note(.*?)\-\-\>/is", "", $tempContent);

		$tempContent = preg_replace("/([\n\r]+)\t+/s", "\\1", $tempContent);
		$tempContent = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $tempContent);
		$tempContent = str_replace("{LF}", "<?=\"\\n\"?>", $tempContent);

		$tempContent = preg_replace("/$tempVarFormat/", "{\\1}", $tempContent);
		$tempContent = preg_replace("/\{\{$tempVarFormat\}(.*?)\}/", "{\\1\\2}", $tempContent);
		$tempContent = preg_replace("/\{$tempVarFormat\}/e", "\$this->TransVar('<?=\\1?>')", $tempContent);

		$tempContent = preg_replace("/[\n\r\t]*\{template\s+([a-z0-9_\/]+)\}[\n\r\t]*/is", "\n<? include \$this->GetHtmFile('\\1'); ?>\n", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{templatecss\s+([a-z0-9_\/]+)\}[\n\r\t]*/is", "\n<? echo \$this->GetCssFile('\\1'); ?>\n", $tempContent);

		$tempContent = preg_replace("/[\n\r\t]*\{url\s+([a-z0-9_]+)\-\>([a-z0-9]+)\s*\}[\n\r\t]*/i", "<? echo Lfly::FormatURL('\\1', '\\2'); ?>", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{url\s+([a-z0-9_]+)\-\>([a-z0-9]+)\s+(.+?)\}[\n\r\t]*/ie", "\$this->StripVarTag('<? echo Lfly::FormatURL(\'\\1\', \'\\2\', \\3); ?>')", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{aparea\s+([a-z0-9_]+)\}[\n\r\t]*/i", "<? echo AdPlace_Mdl_AdPlace::CompileApArea('\\1'); ?>", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{aparea\s+(.+?)\}[\n\r\t]*/ie", "\$this->StripVarTag('<? echo AdPlace_Mdl_AdPlace::CompileApArea(\\1); ?>')", $tempContent);

		$tempContent = preg_replace("/[\n\r\t]*\{eval\s+(.+?)\}[\n\r\t]*/ies", "\$this->StripVarTag('<? \\1 ?>')", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/ies", "\$this->StripVarTag('<? echo \\1; ?>')", $tempContent);
		$tempContent = preg_replace("/([\n\r\t]*)\{elseif\s+(.+?)\}([\n\r\t]*)/ies", "\$this->StripVarTag('\\1<? } elseif(\\2) { ?>\\3')", $tempContent);
		$tempContent = preg_replace("/([\n\r\t]*)\{else\}([\n\r\t]*)/is", "\\1<? } else { ?>\\2", $tempContent);

		for ($i=0; $i<5; $i++)
		{
			$tempContent = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/loop\}[\n\r\t]*/ies", "\$this->StripVarTag('<? if(is_array(\\1)) { foreach(\\1 as \\2) { ?>','\\3<? } } ?>')", $tempContent);
			$tempContent = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r\t]*(.+?)[\n\r\t]*\{\/loop\}[\n\r\t]*/ies", "\$this->StripVarTag('<? if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>','\\4<? } } ?>')", $tempContent);
			$tempContent = preg_replace("/([\n\r\t]*)\{if\s+(.+?)\}([\n\r]*)(.+?)([\n\r]*)\{\/if\}([\n\r\t]*)/ies", "\$this->StripVarTag('\\1<? if(\\2) { ?>\\3','\\4\\5<? } ?>\\6')", $tempContent);
		}

		$tempContent = preg_replace("/\{$tempConstFormat\}/s", "<?=\\1?>", $tempContent);
		$tempContent = preg_replace("/[\n\r\t]*\{block\s+([a-zA-Z0-9_]+)\}(.+?)\{\/block\}/ies", "\$this->StripBlock('\\1', '\\2')", $tempContent);
		//$tempContent = preg_replace("/\"(http)?[\w\.\/:]+\?[^\"]+?&[^\"]+?\"/e", "\$this->TransAmp('\\0')", $tempContent);

		$tempContent = "<? !defined('WEB_IN') and exit(); ?>$tempContent";
		$tempContent = preg_replace("/\s+\?\>[\n\r]*\<\?\s+/s", "\n", $tempContent);

		if (!@$fp = fopen($this->htmObjFile, 'wb'))
		{
			exit('Can not write template file: '.basename($this->htmObjFile).'.');
		}
		flock($fp, LOCK_EX);
		fwrite($fp, trim($tempContent));
		flock($fp, LOCK_UN);
		fclose($fp);
		@chmod($this->htmObjFile, 0777);
	}

	/* 获取css调用代码 */
	private function GetCssFile($strFile)
	{
		$this->cssTplFile = $this->tplFolder.'/'.$strFile.'.css';
		$this->cssObjFile = $this->cssObjFolder.'/'.$strFile.'.css';
		$tempCssLinkCode = '<link rel="stylesheet" type="text/css" href="'.$this->cssLinkFolder.'/'.$strFile.'.css" />'."\n";
		if ($this->tplDefaultFolder!='' && !is_file($this->cssTplFile))
		{
			$this->cssTplFile = $this->tplDefaultFolder.'/'.$strFile.'.css';
		}
		if (!is_file($this->cssObjFile) || @filemtime($this->cssTplFile) > @filemtime($this->cssObjFile))
		{
			$this->CompileCss();
		}
		return $tempCssLinkCode;
	}

	/* 获取htm模板文件 */
	private function GetHtmFile($strFile)
	{
		$this->htmTplFile = $this->tplFolder.'/'.$strFile.'.htm';
		$this->htmObjFile = $this->htmObjFolder.'/'.$strFile.'.tpl.php';
		if ($this->tplDefaultFolder!='' && !is_file($this->htmTplFile))
		{
			$this->htmTplFile = $this->tplDefaultFolder.'/'.$strFile.'.htm';
		}
		if (!is_file($this->htmObjFile) || @filemtime($this->htmTplFile) > @filemtime($this->htmObjFile))
		{
			$this->CompileHtm();
		}
		return $this->htmObjFile;
	}

	/* 字符串区域变量格式化 */
	private function StripBlock($strVar, $strTxt)
	{
		$strTxt = str_replace('\"', '"', $strTxt);
		$strTxt = preg_replace("/<\?=\\\$(.+?)\?>/", "{\$\\1}", $strTxt);
		preg_match_all("/<\?=(.+?)\?>/e", $strTxt, $constary);
		$constadd = '';
		$constary[1] = array_unique($constary[1]);
		foreach ($constary[1] as $const)
		{
			$constadd .= '$__'.$const.' = '.$const.";\n";
		}
		$strTxt = preg_replace("/<\?=(.+?)\?>/", "{\$__\\1}", $strTxt);
		$strTxt = str_replace('?>', "\n\$$strVar .= <<<EOF\n", $strTxt);
		$strTxt = str_replace('<?', "\nEOF;\n", $strTxt);
		return "\n<?\n$constadd\$$strVar = <<<EOF\n".$strTxt."\nEOF;\n?>\n";
	}

	/* 函数等特殊标记代码处理 */
	private function StripVarTag($strExpr, $strStatement = '')
	{
		$strExpr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $strExpr));
		$strStatement = str_replace("\\\"", "\"", $strStatement);
		return $strExpr.$strStatement;
	}

	/* url地址符号处理 */
	private function TransAmp($strVar)
	{
		$strVar = str_replace('&', '&amp;', $strVar);
		$strVar = str_replace('&amp;amp;', '&amp;', $strVar);
		$strVar = str_replace('\"', '"', $strVar);
		return $strVar;
	}

	/* 变量格式化处理 */
	private function TransVar($strVar)
	{
		return str_replace(array("\\\"", '{', '}'), array("\"", '', ''), preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $strVar));
	}

}	//end class

?>